package com.tc.data.mybatis.plugin;

import com.tc.data.mybatis.converter.SqlConverter;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;

/**
 * 分表拦截器
 * 
 * @author Anders Zhu
 * 
 */
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class ShardingPlugin implements Interceptor {

	private static final Logger LOGGER = LoggerFactory.getLogger(ShardingPlugin.class);

	private SqlConverter sqlConverter;

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		String debugInfo = "[" + invocation.toString() + "]";

		LOGGER.debug("get into sharding plugin {}", debugInfo);

		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();

		String sql = statementHandler.getBoundSql().getSql();
		LOGGER.debug("original sql : {}", sql);

		String targetSql = sqlConverter.convert(sql, statementHandler);
		LOGGER.debug("converted sql : {}", targetSql);

		if (!sql.equals(targetSql)) {
			Field field = BoundSql.class.getDeclaredField("sql");
			ReflectionUtils.makeAccessible(field);
			ReflectionUtils.setField(field, statementHandler.getBoundSql(), targetSql);
		}

		try {
			return invocation.proceed();
		} catch (Throwable e) {
			throw e;
		} finally {
			LOGGER.debug("get out sharding plugin {}", debugInfo);
		}
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
	}

	public SqlConverter getSqlConverter() {
		return sqlConverter;
	}

	public void setSqlConverter(SqlConverter sqlConverter) {
		this.sqlConverter = sqlConverter;
	}

}
